package com.zwim.core;

import com.zwim.common.NullWritable;
import com.zwim.common.ZWImConstant;
import com.zwim.core.model.MethodInvokeMeta;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;


import java.lang.reflect.Method;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@Component
public class RequestDispatcher implements ApplicationContextAware {
    private ExecutorService executorService= Executors.newFixedThreadPool(ZWImConstant.getMaxThreads());
    private ApplicationContext app;
    public void dispatcher(final ChannelHandlerContext ctx, final MethodInvokeMeta invokeMeta){

        executorService.submit(()->{
            ChannelFuture f=null;
            try {
                Class<?> interfaceClass=invokeMeta.getInterfaceClass();
                String name =invokeMeta.getMethodName();
                Object[] args=invokeMeta.getArgs();
                Class<?>[] parameterTypes = invokeMeta.getParameterType();
                Object targetObject = app.getBean(interfaceClass);
                Method method = targetObject.getClass().getMethod(name, parameterTypes);
                Object obj = method.invoke(targetObject, args);
                if (obj == null) {
                    f = ctx.writeAndFlush(NullWritable.getInstance());
                } else {
                    f = ctx.writeAndFlush(obj);
                }
                f.addListener(ChannelFutureListener.CLOSE);

            }catch (Exception e){

                f=ctx.writeAndFlush();
            }finally {
                f.addListener(ChannelFutureListener.CLOSE);
            }
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.app=applicationContext;
    }
}
